#include "dlgwrpstdio.h"
#include "ui_dlgwrpstdio.h"
#include <QSettings>
#include <QProcessEnvironment>
#include <QFileDialog>
#include "tb_interface.h"
#include "cmdlineparser.h"
int i_instance = 0;
int i_stdin = 0;
int i_stdout = 0;
int i_stderr = 0;

using namespace TASKBUS;
extern cmdlineParser args;
extern bool bfinished;
DlgWrpStdio::DlgWrpStdio(QWidget *parent) :
	QDialog(parent),
	ui(new Ui::DlgWrpStdio),
	m_process(new QProcess(this))
{
	ui->setupUi(this);
	loadIni();
	i_instance = args.toInt("instance",0);
	i_stdin = args.toInt("stdin",0);
	i_stdout = args.toInt("stdout",0);
	i_stderr = args.toInt("stderr",0);
	connect(m_process,&QProcess::started,this,
			&DlgWrpStdio::slot_started,Qt::QueuedConnection);
	connect(m_process,
			static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>
			(&QProcess::finished),
			this,&DlgWrpStdio::slot_stopped,Qt::QueuedConnection);
	connect(m_process,&QProcess::readyReadStandardOutput,this,
			&DlgWrpStdio::slot_readyReadStandardOutput,Qt::QueuedConnection);
	connect(m_process,&QProcess::readyReadStandardError,this,
			&DlgWrpStdio::slot_readyReadStandardError,Qt::QueuedConnection);
	connect(m_process,&QProcess::bytesWritten,this,
			&DlgWrpStdio::slot_sended,Qt::QueuedConnection);

	if (i_instance)
	{
		ui->lineEdit_parasec->setText(QString::fromStdString(args.toString("cmdline","")));
		ui->lineEdit_prgPath->setText(QString::fromStdString(args.toString("exe","")));
		ui->lineEdit_workingDir->setText(QString::fromStdString(args.toString("directory","./")));
		ui->checkBox_errRestart->setChecked(args.toInt("error_retsart",1)?true:false);
		m_bHide = args.toInt("hide",1)?true:false;
		//Env
		std::vector<std::string> venv = args.toStringArray("env");
		for (std::string e:venv)
		{
			ui->plainTextEdit_extraEnv->appendPlainText(QString::fromStdString(e)+"\n");
		}
	}

}

DlgWrpStdio::~DlgWrpStdio()
{
	cmd_stop();
	if (m_plistenThd)
	{
		m_plistenThd->terminate();
		m_plistenThd->wait();
	}
	delete ui;
}

void DlgWrpStdio::run()
{
	if (m_plistenThd==nullptr)
	{
		m_plistenThd = new listen_thread(this);
		connect(m_plistenThd,&listen_thread::quit_app,
				this,&DlgWrpStdio::slot_quit,Qt::QueuedConnection);
		connect(m_plistenThd,&listen_thread::new_package,
				this,&DlgWrpStdio::slot_newPackage
				);
		m_plistenThd->start();
	}
	on_pushButton_start_clicked();
}
QStringList  DlgWrpStdio::split_cmd(QString cmdline)
{
	QStringList lstCmds;
	std::string cmdstring = ui->lineEdit_parasec->text().toStdString();
	std::string curr;
	bool quct = false;
	for (char c:cmdstring)
	{
		if (c=='"')
		{
			if (quct)
			{
				quct = false;
				if (curr.size())
					lstCmds << QString::fromStdString(curr);
				curr = "";
			}
			else
				quct = true;
		}
		else if (c>=0 && c<=' ')
		{
			if (quct==false)
			{
				if (curr.size())
					lstCmds << QString::fromStdString(curr);
				curr = "";
			}
			else
				curr.push_back(c);
		}
		else
			curr.push_back(c);
	}
	if (curr.size())
		lstCmds << QString::fromStdString(curr);
	return lstCmds;
}
bool DlgWrpStdio::cmd_start()
{
	if (m_timerId==-1)
		m_timerId = startTimer(200);
	if (m_process->state()!=QProcess::NotRunning)
		return false;
	const QString exe = ui->lineEdit_prgPath->text();
	const QString cmd = ui->lineEdit_parasec->text();
	QFileInfo cmdinfo(exe);
	QString command = "\"" + cmdinfo.absoluteFilePath() +"\"";

	if (cmd.size())
		command += " " + cmd;

	//设置当前路径
	if (ui->lineEdit_workingDir->text().length())
		m_process->setWorkingDirectory(ui->lineEdit_workingDir->text());
	else
		m_process->setWorkingDirectory(cmdinfo.absolutePath());


	//准备环境变量
	QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
	const QString newEnv = ui->plainTextEdit_extraEnv->toPlainText();
	const QStringList newEnvPai = newEnv.split("\n");
	foreach(QString evs, newEnvPai)
	{
		const QString tvs = evs.trimmed();
		const QStringList lst_kv = tvs.split("=");
		if (lst_kv.size()!=2)
			continue;
		QString skey = lst_kv.first().trimmed();
		QString sval = lst_kv.last().trimmed();
		if (env.contains(skey))
		{
			QString oldval = env.value(skey);
			env.insert(skey,sval+";"+oldval);
		}
		else
			env.insert(skey,sval);
	}
	m_process->setProcessEnvironment(env);
	m_process->startCommand(command);
	return true;
}


bool DlgWrpStdio::cmd_stop()
{
	if (m_process->state()!=QProcess::Running)
		return false;
	m_process->kill();
	return true;
}

void DlgWrpStdio::slot_started()
{
	ui->pushButton_start->setText(tr("Stop"));
	ui->pushButton_start->setEnabled(true);
}

void DlgWrpStdio::slot_stopped()
{
	ui->pushButton_start->setText(tr("Start"));
	ui->pushButton_start->setEnabled(true);

	this->show();
	if (ui->checkBox_errRestart->isChecked() && bfinished==false && m_bPushStop==false)
	{
		m_nRestartCnt = 15;
	}
}

void DlgWrpStdio::slot_readyReadStandardOutput()
{
	QByteArray arred = m_process->readAllStandardOutput();
	if (i_stdout)
	{
		push_subject(i_stdout,i_instance,arred.size(),(const unsigned char *)arred.constData());
	}
}


void DlgWrpStdio::slot_readyReadStandardError()
{
	QByteArray arred =m_process->readAllStandardError();
	if (i_stderr)
	{
		push_subject(i_stderr,i_instance,arred.size(),(const unsigned char *)arred.constData());
	}
	else
		fwrite(arred.constData(),1,arred.size(),stderr);

}

void DlgWrpStdio::slot_sended(qint64/* b*/)
{

}

void DlgWrpStdio::slot_newPackage(QByteArray arr)
{
	if (isRunning())
	{
			m_process->write(arr);
	}
}

bool DlgWrpStdio::isRunning ()
{
	return m_process->state()==QProcess::NotRunning?false:true;
}

void DlgWrpStdio::on_pushButton_start_clicked()
{
	if (!i_instance)
		saveIni();
	if (m_nRestartCnt>=0)
	{
		m_nRestartCnt = -1;
		ui->pushButton_start->setText(tr("Start"));
		return;
	}
	if (isRunning()==false)
	{
		m_bPushStop = false;
		cmd_start();
	}
	else
	{
		m_bPushStop = true;
		cmd_stop();
	}
}

void DlgWrpStdio::timerEvent(QTimerEvent *event)
{
	static int ct = 0;
	if (event->timerId()==m_timerId)
	{
		if (isRunning())
		{
			ct = 0;
			if (m_bHide && isVisible())
				hide();
		}
		else
		{
			if (m_bHide && !isVisible())
				show();
			if (++ct % 10==0)
			{
				fprintf(stderr,"waiting for start...");
				fflush(stderr);
			}
			if (ct >= 300)
			{
				fprintf(stderr,"Failed to start");
				fflush(stderr);
			}
			if (m_nRestartCnt>=0)
			{
				ui->pushButton_start->setText(tr("ReStarting %1").arg(m_nRestartCnt));
				--m_nRestartCnt;
				if (m_nRestartCnt==-1)
				{
					on_pushButton_start_clicked();
					++m_nRestartTimes;
					ui->checkBox_errRestart->setText(QString("Err Restart for %1 times.").arg(m_nRestartTimes));
				}
			}
		}

	}
}

void DlgWrpStdio::on_toolButton_path_clicked()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat);
	QString hist_prgpath = settings.value("history/prgpath","/").toString();
	QString dirt = QFileDialog::getOpenFileName(this,tr("Get Exec Path"),hist_prgpath);
	if (dirt.length())
	{
		ui->lineEdit_prgPath->setText(dirt);
		settings.setValue("history/prgpath",dirt);
	}
}

void DlgWrpStdio::on_toolButton_workingDir_clicked()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat);
	QString hist_workingdir = settings.value("history/workingdir","/").toString();
	QString dirt = QFileDialog::getExistingDirectory(this,tr("GetPath"),hist_workingdir);
	if (dirt.length())
	{
		ui->lineEdit_workingDir->setText(hist_workingdir);
		settings.setValue("history/workingdir",dirt);
	}

}
void DlgWrpStdio::loadIni()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat);
	QString lineEdit_parasec = settings.value("settings/lineEdit_parasec","").toString();
	ui->lineEdit_parasec->setText(lineEdit_parasec);
	QString lineEdit_prgPath = settings.value("settings/lineEdit_prgPath","test.exe").toString();
	ui->lineEdit_prgPath->setText(lineEdit_prgPath);
	QString lineEdit_workingDir = settings.value("settings/lineEdit_workingDir","/home/data").toString();
	ui->lineEdit_workingDir->setText(lineEdit_workingDir);
	QString plainTextEdit_extraEnv = settings.value("settings/plainTextEdit_extraEnv","").toString();
	ui->plainTextEdit_extraEnv->setPlainText( plainTextEdit_extraEnv);
	int checkBox_errRestart = settings.value("settings/checkBox_errRestart",0).toInt();
	ui->checkBox_errRestart->setChecked(checkBox_errRestart?true:false);

}
void DlgWrpStdio::saveIni()
{
	QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat);

	QString lineEdit_parasec = ui->lineEdit_parasec->text();
	settings.setValue("settings/lineEdit_parasec",lineEdit_parasec);
	QString lineEdit_prgPath = ui->lineEdit_prgPath->text();
	settings.setValue("settings/lineEdit_prgPath",lineEdit_prgPath);
	QString lineEdit_workingDir = ui->lineEdit_workingDir->text();
	settings.setValue("settings/lineEdit_workingDir",lineEdit_workingDir);
	QString plainTextEdit_extraEnv = ui->plainTextEdit_extraEnv->toPlainText();
	settings.setValue("settings/plainTextEdit_extraEnv",plainTextEdit_extraEnv);
	int checkBox_errRestart = ui->checkBox_errRestart->isChecked()?1:0;
	settings.setValue("settings/checkBox_errRestart",checkBox_errRestart);
}

void DlgWrpStdio::slot_quit()
{
	if (m_process)
	{
		m_process->terminate();
		m_process->waitForFinished(1000);
		m_process->kill();
		m_process->waitForFinished(1000);
	}
	close();
}
